extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}


#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>
/**#include <opencv2/opencv.hpp>*/

#include <cstring>

#include <sstream>
#include <vector>

#include <iostream>
#include <string>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#define PORT 9000 // 选择一个未被占用的端口

AVFrame *yuv = nullptr;
AVDictionary *codec_options = nullptr;
AVCodecContext *codec_context = nullptr;
AVFormatContext *format_context = nullptr;
SwsContext *sws_context = nullptr;
AVPacket pack = {0};
AVStream *vs;
int vpts = 0;
long lastSocketRevTime = 0;
int newSocketId = 0;


void set_non_blocking(int sock_fd)
{
    fcntl(sock_fd, F_SETFL, fcntl(sock_fd, F_GETFL, 0) | O_NONBLOCK);
}


int main(int argc, char *argv[])
{

    int width = 1280;
    int height = 720;

    vpts = 0;
    sws_context = sws_getCachedContext(sws_context,
                                       width,
                                       height,
                                       AV_PIX_FMT_BGR24, // 源格式
                                       width,
                                       height,
                                       AV_PIX_FMT_YUV420P, // 目标格式
                                       SWS_BILINEAR,       // 尺寸变化使用算法
                                       0, 0, 0);

    printf("start init rtmp2....\n");
    if (NULL == sws_context)
    {
        printf("sws_getCachedContext error\n");
        return 0;
    }

    // 3.初始化输出的数据结构
    yuv = av_frame_alloc();
    yuv->format = AV_PIX_FMT_YUV420P;
    yuv->width = width;
    yuv->height = height;
    yuv->pts = 0;

    printf("start init rtmp3....");
    // 分配yuv空间
    int ret_code = av_frame_get_buffer(yuv, 32);
    if (0 != ret_code)
    {
        printf("yuv init fail");
        return 0;
    }

    printf("start init rtmp4....");
    // 4.初始化编码上下文
    // 4.1找到编码器
    const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (NULL == codec)
    {
        printf("Can't find h264 encoder.");
        return 0;
    }

    printf("start init rtmp5....");
    // 4.2创建编码器上下文
    codec_context = avcodec_alloc_context3(codec);
    if (NULL == codec_context)
    {
        printf("avcodec_alloc_context3 failed.");
        return 0;
    }

    // 4.3配置编码器参数
    codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    codec_context->codec_id = codec->id;
    codec_context->thread_count = 4;

    int fps = 25;
    // 压缩后每秒视频的bit流 0.5M
    // codec_context->bit_rate = 0.3 * 1024 * 1024 * 8;
    codec_context->bit_rate = 1024 * 1024 * 1;
    codec_context->width = width;
    codec_context->height = height;
    codec_context->time_base = {1, fps};
    codec_context->framerate = {fps, 1};

    // 画面组的大小，多少帧一个关键帧
    codec_context->gop_size = 20;
    codec_context->max_b_frames = 0;
    codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
    codec_context->qmin = 10;
    codec_context->qmax = 51;

    printf("start init rtmp6....");
    //(baseline | high | high10 | high422 | high444 | main)
    av_dict_set(&codec_options, "profile", "main", 0);
    av_dict_set(&codec_options, "preset", "faster", 0);
    av_dict_set(&codec_options, "tune", "zerolatency", 0);

    // 4.4打开编码器上下文
    ret_code = avcodec_open2(codec_context, codec, &codec_options);
    if (0 != ret_code)
    {

        return 0;
    }
    printf("avcodec_open2 success!");

    // 5.输出封装器和视频流配置
    // 5.1创建输出封装器上下文
    // rtmp flv封装器
    std::string push_url = "rtmp://121.43.227.156/live/7CTDM5E00BTC13-165-0-7_ai?66ab580dfced4365adf9d6cc2fd5a8fc";
    ret_code = avformat_alloc_output_context2(&format_context, 0, "flv", push_url.c_str());
    if (0 != ret_code)
    {

        return 0;
    }

    // 5.2添加视频流
    vs = avformat_new_stream(format_context, NULL);
    if (NULL == vs)
    {
        printf("avformat_new_stream failed.");
        return 0;
    }

    vs->codecpar->codec_tag = 0;
    // 从编码器复制参数
    avcodec_parameters_from_context(vs->codecpar, codec_context);
    av_dump_format(format_context, 0, push_url.c_str(), 1);

    // 打开rtmp 的网络输出IO
    ret_code = avio_open(&format_context->pb, push_url.c_str(), AVIO_FLAG_WRITE);
    if (0 != ret_code)
    {
        printf("avio_open failed.");
        return 0;
    }

    // 写入封装头
    ret_code = avformat_write_header(format_context, NULL);
    if (0 != ret_code)
    {
        printf("avformat_write_header failed.");
        return 0;
    }

    // return;
//    av_register_all();

    AVFormatContext *pFormatCtx = nullptr;
    if (avformat_open_input(&pFormatCtx, "http://121.43.227.156:8080/live/1581F6Q8D245600EG8LN-81-0-0.flv", nullptr, nullptr) != 0)
    {
        printf("live pull failed,retry1..");
        return -1;
    }

    if (avformat_find_stream_info(pFormatCtx, nullptr) < 0)
    {
        printf("live pull failed,retry2..");
        return -1;
    }

    int video_stream_index = -1;
    for (unsigned i = 0; i < pFormatCtx->nb_streams; i++)
    {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            video_stream_index = i;
            break;
        }
    }

    if (video_stream_index == -1)
    {
        // 错误处理：没有找到视频流
        printf("live pull failed,retry3..");
        return -1;
    }

    AVCodecParameters *pCodecParams = pFormatCtx->streams[video_stream_index]->codecpar;
    const AVCodec *pCodec = avcodec_find_decoder(pCodecParams->codec_id);
    if (pCodec == nullptr)
    {
        // 错误处理：找不到解码器
        printf("live pull failed,retry4..");
        return -1;
    }

    AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
    if (!pCodecCtx)
    {
        avcodec_free_context(&pCodecCtx);
        printf("live pull failed,retry5..");
        // 错误处理
        return -1;
    }

    if (avcodec_parameters_to_context(pCodecCtx, pCodecParams) < 0)
    {
        avcodec_free_context(&pCodecCtx);
        // 错误处理
        printf("live pull failed,retry6..");
        return -1;
    }

    if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0)
    {
        avcodec_free_context(&pCodecCtx);
        // 错误处理
        printf("live pull failed,retry7..");
        return -1;
    }

    AVPacket *pPacket = av_packet_alloc();
    AVFrame *pFrame = av_frame_alloc();
    SwsContext *sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
                                         pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
                                         AV_PIX_FMT_BGR24, SWS_BILINEAR, nullptr, nullptr, nullptr);

    int i = 0;
    while (av_read_frame(pFormatCtx, pPacket) >= 0)
    {
        if (pPacket->stream_index == video_stream_index)
        {
            if (avcodec_send_packet(pCodecCtx, pPacket) == 0)
            {
                while (avcodec_receive_frame(pCodecCtx, pFrame) == 0)
                {
                    auto height = pCodecCtx->height;
                    auto width = pCodecCtx->width;
                    // 分配输出图像空间
                    cv::Mat frameMat(height + height / 2, width, CV_8UC3); // BGR 格式，高度是原始高度的1.5倍（因为YUV420P是隔行存储UV）

                    // 转换帧
                    uint8_t *data[AV_NUM_DATA_POINTERS] = {0};
                    int linesize[AV_NUM_DATA_POINTERS] = {0};
                    av_image_fill_arrays(data, linesize, frameMat.data, AV_PIX_FMT_BGR24, width, height, 1);

                    sws_scale(sws_ctx,
                              (const uint8_t *const *)pFrame->data,
                              pFrame->linesize,
                              0,
                              height,
                              data,
                              linesize);

                    cv::Mat image = frameMat(cv::Rect(0, 0, width, height));
                    printf("================...\n");
                    // int ret=sendImage(clientSocket,result);
                    // if(ret<0){
                    // 	finished=true;
                    // }

                    // printf("send result:%d",ret);

                    // i++;

                    uint8_t *in_data[AV_NUM_DATA_POINTERS] = {0};
                    int in_size[AV_NUM_DATA_POINTERS] = {0};
                    in_data[0] = image.data;
                    // 一行（宽）数据的字节数
                    in_size[0] = image.cols * image.elemSize();
                    int h = sws_scale(sws_context,
                                      in_data,
                                      in_size,
                                      0,
                                      image.rows,
                                      yuv->data,
                                      yuv->linesize);
                    if (h <= 0)
                    {
                        printf("sws_scale failed:%d", h);
                        return -1;
                    }

                    // INFO("================22222");
                    //  av_packet_unref(&pack);
                    //   h264编码
                    yuv->pts = vpts;
                    vpts++;

                    int ret_code = avcodec_send_frame(codec_context, yuv);
                    if (0 != ret_code)
                    {
                        return -1;
                    }

                    ret_code = avcodec_receive_packet(codec_context, &pack);

                    if (0 != ret_code || pack.size <= 0)
                    { //
                        printf("avcodec_receive_packet:%d", ret_code);
                        return -1;
                    }

                    // INFO("================333333");
                    /* else {
                         cout << "avcodec_receive_packet contiune." << endl;
                         continue;
                     }*/
                    // 推流
                    pack.pts = av_rescale_q(pack.pts, codec_context->time_base, vs->time_base);
                    pack.dts = av_rescale_q(pack.dts, codec_context->time_base, vs->time_base);
                    pack.duration = av_rescale_q(pack.duration,
                                                 codec_context->time_base,
                                                 vs->time_base);
                    ret_code = av_interleaved_write_frame(format_context, &pack);
                    if (0 != ret_code)
                    {
                        printf("pack is error:%d", ret_code);
                    }

                    //ii++;
                    // 每3帧跳一帧
                    //if (i >= 3)
                    //{
                        // 发送给盒子
                        //sendImage(image);
                        //i = 0;
                        //continue;
                    //}

                    image.release();
                }
            }
        }
        av_packet_unref(pPacket);
    }

    printf("==========1");

    // 释放资源
    sws_freeContext(sws_ctx);
    av_frame_free(&pFrame);
    av_packet_free(&pPacket);
    avcodec_free_context(&pCodecCtx);

    // 关闭客户端连接
    close(newSocketId);
    std::cout << "Connection closed." << std::endl;

    return 0;
}
